/*
 *
 * Copyright (c) 2016 Allwinnertech Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 */
/*
 * A V4L2 driver for GalaxyCore PR2000k cameras.
 *
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <linux/clk.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-mediabus.h>
#include <linux/io.h>

#include "pr2000_driver/pr2000_main.h"

#include "camera.h"


MODULE_AUTHOR("zhang");
MODULE_DESCRIPTION("A low-level driver for PR2000K sensors");
MODULE_LICENSE("GPL");


//for internel driver debug
#define DEV_DBG_EN   		0
#if(DEV_DBG_EN == 1)		
#define vfe_dev_dbg(x,arg...) printk("[CSI_DEBUG][PR2000k]"x,##arg)
#else
#define vfe_dev_dbg(x,arg...) 
#endif
#define vfe_dev_err(x,arg...) printk("[CSI_ERR][PR2000k]"x,##arg)
#define vfe_dev_print(x,arg...) printk("[CSI][PR2000k]"x,##arg)

#define LOG_ERR_RET(x)  { \
                          int ret;  \
                          ret = x; \
                          if(ret < 0) {\
                            vfe_dev_err("error at %s\n",__func__);  \
                            return ret; \
                          } \
                        }

//define module timing
#define MCLK (36*1000*1000)
#define VREF_POL          V4L2_MBUS_HSYNC_ACTIVE_HIGH
#define HREF_POL          V4L2_MBUS_HSYNC_ACTIVE_HIGH
#define CLK_POL           V4L2_MBUS_PCLK_SAMPLE_FALLING
#define V4L2_IDENT_SENSOR 0x2000

//define the voltage level of control signal
#define CSI_STBY_ON			1
#define CSI_STBY_OFF 		0
#define CSI_RST_ON			0
#define CSI_RST_OFF			1
#define CSI_PWR_ON			1
#define CSI_PWR_OFF			0

#define regval_list reg_list_a8_d8
#define REG_TERM 0xff
#define VAL_TERM 0xff
#define REG_DLY  0xffff


/*
 * Our nominal (default) frame rate.
 */
#define SENSOR_FRAME_RATE 50

/*
 * The PR2000 sits on i2c with ID 0xb8
 */
#define I2C_ADDR 0xb8
#define SENSOR_NAME "pr2000"
/*
 * Information we maintain about a known sensor.
 */
struct sensor_format_struct;  /* coming later */

struct cfg_array { /* coming later */
	struct regval_list * regs;
	int size;
};

static inline struct sensor_info *to_state(struct v4l2_subdev *sd)
{
  return container_of(sd, struct sensor_info, sd);
}
 
static struct regval_list sensor_default_regs[] = {	//27M 1280*720 YUV 8bit 25fps

#if 0
	{0xff, 0x00},
	{0x10, 0x82},
	{0x11, 0x00},
	{0x12, 0x00},
	{0x13, 0x11},
	{0x14, 0x21},
	{0x15, 0x44},
	{0x16, 0x0d},
	{0x40, 0x00},
	{0x47, 0x3a},
	{0x4e, 0x3f},
	{0x80, 0x56},
	{0x81, 0x0e},
	{0x82, 0x0d},
	{0x84, 0x30},
	{0x86, 0x20},
	{0x87, 0x00},
	{0x8a, 0x00},
	{0x90, 0x00},
	{0x91, 0x00},
	{0x92, 0x00},
	{0x94, 0xff},
	{0x95, 0x00},
	{0x96, 0x00},
	{0xa0, 0x01},
	{0xa1, 0xe3},
	{0xa4, 0x01},
	{0xa5, 0xe3},
	{0xa6, 0x00},
	{0xa7, 0x12},
	{0xa8, 0x00},
	{0xd0, 0x30},
	{0xd1, 0x08},
	{0xd2, 0x21},
	{0xd3, 0x00},
	{0xd8, 0x34},
	{0xd9, 0x08},
	{0xda, 0x21},
	{0xe0, 0x39},
	{0xe1, 0x90},
	{0xe2, 0x39},
	{0xe3, 0x19},
	{0xe4, 0x19},
	{0xea, 0x02},
	{0xeb, 0xff},
	{0xf1, 0x44},
	{0xf2, 0x01},
	{0xff, 0x01},
	{0x00, 0xe4},
	{0x01, 0x61},
	{0x02, 0x00},
	{0x03, 0x56},
	{0x04, 0x0c},
	{0x05, 0x88},
	{0x06, 0x04},
	{0x07, 0xb2},
	{0x08, 0x44},
	{0x09, 0x34},
	{0x0a, 0x02},
	{0x0b, 0x14},
	{0x0c, 0x04},
	{0x0d, 0x08},
	{0x0e, 0x5e},
	{0x0f, 0x5e},
	{0x10, 0x26},
	{0x11, 0x01},
	{0x12, 0x45},
	{0x13, 0x0c },
	{0x14, 0x00},
	{0x15, 0x1b },
	{0x16, 0xd0},
	{0x17, 0x00},
	{0x18, 0x41},
	{0x19, 0x46},
	{0x1a, 0x22},
	{0x1b, 0x05},
	{0x1c, 0xea},
	{0x1d, 0x45},
	{0x1e, 0x4c},
	{0x1f, 0x00},
	{0x20, 0x88},
	{0x21, 0x82},
	{0x22, 0x90},
	{0x23, 0x80},
	{0x24, 0x80},
	{0x25, 0x80},
	{0x26, 0x84},
	{0x27, 0x82},
	{0x28, 0x00},
	{0x29, 0x7d},
	{0x2a, 0x00},
	{0x2b, 0x00},
	{0x2c, 0x00},
	{0x2d, 0x00},
	{0x2e, 0x00},
	{0x2f, 0x00},
	{0x30, 0x00},
	{0x31, 0x00},
	{0x32, 0xc0},
	{0x33, 0x14},
	{0x34, 0x14},
	{0x35, 0x80},
	{0x36, 0x80},
	{0x37, 0xaa},
	{0x38, 0x48},
	{0x39, 0x08},
	{0x3a, 0x27},
	{0x3b, 0x02},
	{0x3c, 0x01},
	{0x3d, 0x23},
	{0x3e, 0x02},
	{0x3f, 0xc4},
	{0x40, 0x05},
	{0x41, 0x55},
	{0x42, 0x01},
	{0x43, 0x33},
	{0x44, 0x6a},
	{0x45, 0x00},
	{0x46, 0x09},
	{0x47, 0xe2},
	{0x48, 0x01},
	{0x49, 0x00},
	{0x4a, 0x7b},
	{0x4b, 0x60},
	{0x4c, 0x00},
	{0x4d, 0x4a},
	{0x4e, 0x00},
	{0x4f, 0x20},
	{0x50, 0x01},
	{0x51, 0x28},
	{0x52, 0x40},
	{0x53, 0x0c},
	{0x54 ,0x0f},
	{0x55, 0x8d},
	{0x70, 0x06},
	{0x71, 0x08},
	{0x72, 0x0a},
	{0x73, 0x0c},
	{0x74, 0x0e},
	{0x75 ,0x10},
	{0x76, 0x12},
	{0x77, 0x14},
	{0x78, 0x06},
	{0x79, 0x08},
	{0x7a, 0x0a},
	{0x7b, 0x0c},
	{0x7c, 0x0e},
	{0x7d, 0x10},
	{0x7e, 0x12},
	{0x7f, 0x14},
	{0x80, 0x00},
	{0x81, 0x09},
	{0x82 ,0x00},
	{0x83, 0x07},
	{0x84, 0x00},
	{0x85, 0x14},
	{0x86, 0x03},
	{0x87, 0x36},
	{0x88, 0x0c},
	{0x89, 0x76},
	{0x8a, 0x0c},
	{0x8b, 0x76},
	{0x8c, 0x0b},
	{0x8d, 0xe0},
	{0x8e, 0x06},
	{0x8f, 0x66},
	{0x90, 0x06},
	{0x91, 0x8f},
	{0x92, 0x73},
	{0x93, 0x39},
	{0x94, 0x0f},
	{0x95, 0x5e},
	{0x96, 0x09},
	{0x97, 0x26},
	{0x98, 0x1c},
	{0x99, 0x20},
	{0x9a, 0x17},
	{0x9b, 0x70},
	{0x9c, 0x0e},
	{0x9d, 0x10},
	{0x9e, 0x0b},
	{0x9f, 0xb8},
	{0xa0, 0x01},
	{0xa1, 0xc2},
	{0xa2, 0x01},
	{0xa3, 0xb8},
	{0xa4, 0x00},
	{0xa5, 0xe1},
	{0xa6, 0x00},
	{0xa7, 0xc6},
	{0xa8, 0x01},
	{0xa9, 0x7c},
	{0xaa, 0x01},
	{0xab, 0x7c},
	{0xac, 0x00},
	{0xad, 0xea},
	{0xae, 0x00},
	{0xaf, 0xea},
	{0xb0, 0x0b},
	{0xb1, 0x99},
	{0xb2, 0x12},
	{0xb3, 0xca},
	{0xb4, 0x00},
	{0xb5, 0x17},
	{0xb6, 0x08},
	{0xb7, 0xe8},
	{0xb8, 0xb0},
	{0xb9, 0xce},
	{0xba, 0x90},
	{0xbb, 0x00},
	{0xbc, 0x00},
	{0xbd, 0x03},
	{0xbe, 0x05},
	{0xbf, 0x00},
	{0xc0, 0x00},
	{0xc1, 0x1c},
	{0xc2, 0x02},
	{0xc3, 0xd9},
	{0x54, 0x0e},
	{0x54, 0x0f},
#endif

#if 1
{0xff,0x00},
{0x00,0x8b},
{0x01,0xff},
{0x02,0x07},
{0x03,0x70},
{0x04,0x21},
{0x05,0x47},
{0x06,0x0c},
{0x07,0xcc},
{0x08,0x00},
{0x09,0xec},
{0x0a,0x95},
{0x0b,0xda},
{0x0c,0x2e},
{0x0d,0xe6},
{0x0e,0x04},
{0x0f,0xd2},
{0x10,0x83},
{0x11,0x00},
{0x12,0xc0},
{0x13,0x00},
{0x14,0x21},
{0x15,0x44},
{0x16,0x0d},
{0x17,0x00},
{0x18,0x00},
{0x19,0x00},
{0x1a,0x00},
{0x1b,0x00},
{0x1c,0x00},
{0x1d,0x00},
{0x1e,0x00},
{0x1f,0x00},
{0x20,0x00},
{0x21,0x00},
{0x22,0x00},
{0x23,0x00},
{0x24,0x00},
{0x25,0x00},
{0x26,0x00},
{0x27,0x00},
{0x28,0x00},
{0x29,0x00},
{0x2a,0x00},
{0x2b,0x00},
{0x2c,0x00},
{0x2d,0x00},
{0x2e,0x00},
{0x2f,0x00},
{0x30,0x00},
{0x31,0x00},
{0x32,0x00},
{0x33,0x00},
{0x34,0x00},
{0x35,0x00},
{0x36,0x00},
{0x37,0x00},
{0x38,0x00},
{0x39,0x00},
{0x3a,0x00},
{0x3b,0x00},
{0x3c,0x00},
{0x3d,0x00},
{0x3e,0x00},
{0x3f,0x00},
{0x40,0x00},
{0x41,0x88},
{0x42,0x88},
{0x43,0x88},
{0x44,0x03},
{0x45,0x33},
{0x46,0x33},
{0x47,0x3a},
{0x48,0x00},
{0x49,0x0a},
{0x4a,0x73},
{0x4b,0x13},
{0x4c,0x2c},
{0x4d,0x17},
{0x4e,0x3f},
{0x4f,0x00},
{0x50,0x1e},
{0x51,0x09},
{0x52,0x0b},
{0x53,0x0b},
{0x54,0x14},
{0x55,0x0f},
{0x56,0x23},
{0x57,0x0f},
{0x58,0x0f},
{0x59,0x42},
{0x5a,0x40},
{0x5b,0x11},
{0x5c,0x00},
{0x5d,0x40},
{0x5e,0x00},
{0x5f,0x00},
{0x60,0x00},
{0x61,0x00},
{0x62,0x00},
{0x63,0x00},
{0x64,0x00},
{0x65,0x00},
{0x66,0x00},
{0x67,0x00},
{0x68,0x00},
{0x69,0x00},
{0x6a,0x00},
{0x6b,0x00},
{0x6c,0x00},
{0x6d,0x00},
{0x6e,0x00},
{0x6f,0x00},
{0x70,0x00},
{0x71,0xff},
{0x72,0xaa},
{0x73,0x55},
{0x74,0x0a},
{0x75,0x50},
{0x76,0xfa},
{0x77,0xce},
{0x78,0x00},
{0x79,0x00},
{0x7a,0x00},
{0x7b,0x00},
{0x7c,0x00},
{0x7d,0x00},
{0x7e,0x00},
{0x7f,0x00},
{0x80,0x56},
{0x81,0x0e},
{0x82,0x0d},
{0x83,0x20},
{0x84,0x30},
{0x85,0x00},
{0x86,0x30},
{0x87,0x00},
{0x88,0x00},
{0x89,0x00},
{0x8a,0x00},
{0x8b,0x00},
{0x8c,0x00},
{0x8d,0x00},
{0x8e,0x00},
{0x8f,0x00},
{0x90,0xbf},
{0x91,0xf8},
{0x92,0x00},
{0x93,0x00},
{0x94,0x00},
{0x95,0x80},
{0x96,0x00},
{0x97,0x00},
{0x98,0x00},
{0x99,0x81},
{0x9a,0x78},
{0x9b,0x00},
{0x9c,0x00},
{0x9d,0x00},
{0x9e,0x00},
{0x9f,0x00},
{0xa0,0x01},
{0xa1,0xe3},
{0xa2,0x00},
{0xa3,0x00},
{0xa4,0x01},
{0xa5,0xe3},
{0xa6,0x00},
{0xa7,0x12},
{0xa8,0x00},
{0xa9,0x00},
{0xaa,0x00},
{0xab,0x00},
{0xac,0x00},
{0xad,0x00},
{0xae,0x00},
{0xaf,0x00},
{0xb0,0x00},
{0xb1,0x00},
{0xb2,0x00},
{0xb3,0x00},
{0xb4,0x00},
{0xb5,0x00},
{0xb6,0x00},
{0xb7,0x00},
{0xb8,0x00},
{0xb9,0x00},
{0xba,0x00},
{0xbb,0x00},
{0xbc,0x00},
{0xbd,0x00},
{0xbe,0x00},
{0xbf,0x00},
{0xc0,0x00},
{0xc1,0x00},
{0xc2,0x00},
{0xc3,0x00},
{0xc4,0x00},
{0xc5,0x00},
{0xc6,0x00},
{0xc7,0x00},
{0xc8,0x00},
{0xc9,0x00},
{0xca,0x00},
{0xcb,0x00},
{0xcc,0x00},
{0xcd,0x00},
{0xce,0x00},
{0xcf,0x00},
{0xd0,0x30},
{0xd1,0x08},
{0xd2,0x21},
{0xd3,0x00},
{0xd4,0x00},
{0xd5,0x00},
{0xd6,0x00},
{0xd7,0x00},
{0xd8,0x30},
{0xd9,0x08},
{0xda,0x21},
{0xdb,0x00},
{0xdc,0x00},
{0xdd,0x00},
{0xde,0x00},
{0xdf,0x00},
{0xe0,0x35},
{0xe1,0x80},
{0xe2,0x19},
{0xe3,0x00},
{0xe4,0x00},
{0xe5,0x00},
{0xe6,0x00},
{0xe7,0x00},
{0xe8,0x00},
{0xe9,0x00},
{0xea,0x02},
{0xeb,0xff},
{0xec,0x00},
{0xed,0x00},
{0xee,0x00},
{0xef,0x00},
{0xf0,0x00},
{0xf1,0x44},
{0xf2,0x01},
{0xf3,0x00},
{0xf4,0x00},
{0xf5,0x00},
{0xf6,0x00},
{0xf7,0x00},
{0xf8,0x00},
{0xf9,0x00},
{0xfa,0x00},
{0xfb,0x00},
{0xfc,0x20},
{0xfd,0x00},
{0xfe,0x20},
{0xff,0x01},
{0x00,0xe4},
{0x01,0x61},
{0x02,0x00},
{0x03,0x56},
{0x04,0x0c},
{0x05,0x88},
{0x06,0x04},
{0x07,0xb2},
{0x08,0x44},
{0x09,0x34},
{0x0a,0x02},
{0x0b,0x14},
{0x0c,0x04},
{0x0d,0x08},
{0x0e,0x5e},
{0x0f,0x5e},
{0x10,0x26},
{0x11,0x00},
{0x12,0x87},
{0x13,0x24},
{0x14,0x80},
{0x15,0x2a},
{0x16,0x38},
{0x17,0x00},
{0x18,0x80},
{0x19,0x48},
{0x1a,0x6c},
{0x1b,0x05},
{0x1c,0x61},
{0x1d,0x07},
{0x1e,0x7e},
{0x1f,0x80},
{0x20,0xa2},
{0x21,0x6d},
{0x22,0xb7},
{0x23,0x80},
{0x24,0x80},
{0x25,0x80},
{0x26,0x84},
{0x27,0x82},
{0x28,0x00},
{0x29,0xff},
{0x2a,0xff},
{0x2b,0x00},
{0x2c,0x00},
{0x2d,0x00},
{0x2e,0x00},
{0x2f,0x00},
{0x30,0x00},
{0x31,0x00},
{0x32,0xc0},
{0x33,0x14},
{0x34,0x14},
{0x35,0x80},
{0x36,0x80},
{0x37,0xad},
{0x38,0x4b},
{0x39,0x08},
{0x3a,0x21},
{0x3b,0x02},
{0x3c,0x01},
{0x3d,0x23},
{0x3e,0x05},
{0x3f,0xc8},
{0x40,0x05},
{0x41,0x55},
{0x42,0x01},
{0x43,0x38},
{0x44,0x6a},
{0x45,0x00},
{0x46,0x34},
{0x47,0xb0},
{0x48,0x67},
{0x49,0x00},
{0x4a,0x7b},
{0x4b,0x60},
{0x4c,0x00},
{0x4d,0x26},
{0x4e,0x00},
{0x4f,0x20},
{0x50,0x01},
{0x51,0x28},
{0x52,0x40},
{0x53,0x0c},
{0x54,0x0f},
{0x55,0x8d},
{0x56,0x01},
{0x57,0x01},
{0x58,0x01},
{0x59,0x01},
{0x5a,0x01},
{0x5b,0x01},
{0x5c,0x01},
{0x5d,0x01},
{0x5e,0x01},
{0x5f,0x01},
{0x60,0x01},
{0x61,0x01},
{0x62,0x01},
{0x63,0x01},
{0x64,0x01},
{0x65,0x01},
{0x66,0x01},
{0x67,0x01},
{0x68,0x01},
{0x69,0x01},
{0x6a,0x01},
{0x6b,0x01},
{0x6c,0x01},
{0x6d,0x01},
{0x6e,0x01},
{0x6f,0x01},
{0x70,0x06},
{0x71,0x08},
{0x72,0x0a},
{0x73,0x0c},
{0x74,0x0e},
{0x75,0x10},
{0x76,0x12},
{0x77,0x14},
{0x78,0x06},
{0x79,0x08},
{0x7a,0x0a},
{0x7b,0x0c},
{0x7c,0x0e},
{0x7d,0x10},
{0x7e,0x12},
{0x7f,0x14},
{0x80,0x00},
{0x81,0x09},
{0x82,0x00},
{0x83,0x07},
{0x84,0x00},
{0x85,0x14},
{0x86,0x03},
{0x87,0x36},
{0x88,0x06},
{0x89,0x3b},
{0x8a,0x06},
{0x8b,0x3b},
{0x8c,0x08},
{0x8d,0xe8},
{0x8e,0x06},
{0x8f,0x66},
{0x90,0x03},
{0x91,0x47},
{0x92,0x73},
{0x93,0x39},
{0x94,0x0f},
{0x95,0x5e},
{0x96,0x04},
{0x97,0x9c},
{0x98,0x1c},
{0x99,0x20},
{0x9a,0x17},
{0x9b,0x70},
{0x9c,0x0e},
{0x9d,0x10},
{0x9e,0x0b},
{0x9f,0xb8},
{0xa0,0x01},
{0xa1,0xc2},
{0xa2,0x01},
{0xa3,0xb8},
{0xa4,0x00},
{0xa5,0xe1},
{0xa6,0x00},
{0xa7,0xc6},
{0xa8,0x01},
{0xa9,0x7c},
{0xaa,0x01},
{0xab,0x7c},
{0xac,0x00},
{0xad,0xea},
{0xae,0x00},
{0xaf,0xea},
{0xb0,0x05},
{0xb1,0xcc},
{0xb2,0x09},
{0xb3,0x6d},
{0xb4,0x00},
{0xb5,0x17},
{0xb6,0x08},
{0xb7,0xe8},
{0xb8,0xb0},
{0xb9,0xce},
{0xba,0x90},
{0xbb,0x00},
{0xbc,0x00},
{0xbd,0x04},
{0xbe,0x07},
{0xbf,0x80},
{0xc0,0x00},
{0xc1,0x20},
{0xc2,0x04},
{0xc3,0x42},
{0xc4,0x00},
{0xc5,0x00},
{0xc6,0x00},
{0xc7,0x00},
{0xc8,0x00},
{0xc9,0x01},
{0xca,0x01},
{0xcb,0x01},
{0xcc,0x01},
{0xcd,0x01},
{0xce,0x01},
{0xcf,0x01},
{0xd0,0x01},
{0xd1,0x01},
{0xd2,0x01},
{0xd3,0x01},
{0xd4,0x01},
{0xd5,0x01},
{0xd6,0x01},
{0xd7,0x01},
{0xd8,0x01},
{0xd9,0x01},
{0xda,0x01},
{0xdb,0x01},
{0xdc,0x01},
{0xdd,0x01},
{0xde,0x01},
{0xdf,0x01},
{0xe0,0x01},
{0xe1,0x01},
{0xe2,0x01},
{0xe3,0x01},
{0xe4,0x01},
{0xe5,0x01},
{0xe6,0x01},
{0xe7,0x01},
{0xe8,0x01},
{0xe9,0x01},
{0xea,0x01},
{0xeb,0x01},
{0xec,0x01},
{0xed,0x01},
{0xee,0x01},
{0xef,0x01},
{0xf0,0x01},
{0xf1,0x01},
{0xf2,0x01},
{0xf3,0x01},
{0xf4,0x01},
{0xf5,0x01},
{0xf6,0x01},
{0xf7,0x01},
{0xf8,0x01},
{0xf9,0x01},
{0xfa,0x01},
{0xfb,0x01},
{0xfc,0x01},
{0xfd,0x01},
{0xfe,0x01},
{0xff,0x02},
{0x00,0x80},
{0x01,0x20},
{0x02,0x08},
{0x03,0x03},
{0x04,0x53},
{0x05,0x76},
{0x06,0x03},
{0x07,0x53},
{0x08,0x76},
{0x09,0x04},
{0x0a,0x10},
{0x0b,0x18},
{0x0c,0x0c},
{0x0d,0x42},
{0x0e,0x02},
{0x0f,0x02},
{0x10,0x06},
{0x11,0x24},
{0x12,0x00},
{0x13,0x02},
{0x14,0x03},
{0x15,0x00},
{0x16,0x00},
{0x17,0xff},
{0x18,0x00},
{0x19,0x00},
{0x1a,0x00},
{0x1b,0x01},
{0x1c,0x00},
{0x1d,0x00},
{0x1e,0x00},
{0x1f,0x01},
{0x20,0x80},
{0x21,0x20},
{0x22,0x08},
{0x23,0x03},
{0x24,0x53},
{0x25,0x76},
{0x26,0x03},
{0x27,0x53},
{0x28,0x76},
{0x29,0x05},
{0x2a,0x64},
{0x2b,0x18},
{0x2c,0x48},
{0x2d,0x00},
{0x2e,0x81},
{0x2f,0x02},
{0x30,0xd3},
{0x31,0x4d},
{0x32,0x34},
{0x33,0x00},
{0x34,0x00},
{0x35,0x00},
{0x36,0xd3},
{0x37,0x4d},
{0x38,0x34},
{0x39,0x00},
{0x3a,0x00},
{0x3b,0x00},
{0x3c,0x02},
{0x3d,0x02},
{0x3e,0x02},
{0x3f,0x02},
{0x40,0xb1},
{0x41,0x00},
{0x42,0x00},
{0x43,0x00},
{0x44,0x00},
{0x45,0x00},
{0x46,0x00},
{0x47,0x00},
{0x48,0x00},
{0x49,0x00},
{0x4a,0x00},
{0x4b,0x02},
{0x4c,0x02},
{0x4d,0x02},
{0x4e,0x02},
{0x4f,0x02},
{0x50,0x40},
{0x51,0x08},
{0x52,0xce},
{0x53,0x02},
{0x54,0x02},
{0x55,0x02},
{0x56,0x02},
{0x57,0x02},
{0x58,0x00},
{0x59,0x00},
{0x5a,0x00},
{0x5b,0x02},
{0x5c,0x02},
{0x5d,0x02},
{0x5e,0x02},
{0x5f,0x02},
{0x60,0x02},
{0x61,0x02},
{0x62,0x02},
{0x63,0x02},
{0x64,0x02},
{0x65,0x02},
{0x66,0x02},
{0x67,0x02},
{0x68,0x02},
{0x69,0x02},
{0x6a,0x02},
{0x6b,0x02},
{0x6c,0x02},
{0x6d,0x02},
{0x6e,0x02},
{0x6f,0x02},
{0x70,0x02},
{0x71,0x02},
{0x72,0x02},
{0x73,0x02},
{0x74,0x02},
{0x75,0x02},
{0x76,0x02},
{0x77,0x02},
{0x78,0x02},
{0x79,0x02},
{0x7a,0x02},
{0x7b,0x02},
{0x7c,0x02},
{0x7d,0x02},
{0x7e,0x02},
{0x7f,0x02},
{0x80,0x00},
{0x81,0x00},
{0x82,0xa0},
{0x83,0x00},
{0x84,0x07},
{0x85,0x80},
{0x86,0x00},
{0x87,0x6c},
{0x88,0x00},
{0x89,0x80},
{0x8a,0x00},
{0x8b,0x80},
{0x8c,0x10},
{0x8d,0x00},
{0x8e,0x00},
{0x8f,0x00},
{0x90,0x35},
{0x91,0xbb},
{0x92,0x0f},
{0x93,0x01},
{0x94,0x02},
{0x95,0x02},
{0x96,0x02},
{0x97,0x02},
{0x98,0x02},
{0x99,0x02},
{0x9a,0x02},
{0x9b,0x02},
{0x9c,0x02},
{0x9d,0x02},
{0x9e,0x02},
{0x9f,0x02},
{0xa0,0x00},
{0xa1,0x00},
{0xa2,0x00},
{0xa3,0x00},
{0xa4,0x00},
{0xa5,0x02},
{0xa6,0x02},
{0xa7,0x02},
{0xa8,0x00},
{0xa9,0x00},
{0xaa,0x00},
{0xab,0x00},
{0xac,0x00},
{0xad,0x02},
{0xae,0x02},
{0xaf,0x02},
{0xb0,0x02},
{0xb1,0x02},
{0xb2,0x02},
{0xb3,0x02},
{0xb4,0x02},
{0xb5,0x02},
{0xb6,0x02},
{0xb7,0x02},
{0xb8,0x02},
{0xb9,0x02},
{0xba,0x02},
{0xbb,0x02},
{0xbc,0x02},
{0xbd,0x02},
{0xbe,0x02},
{0xbf,0x02},
{0xc0,0x02},
{0xc1,0x02},
{0xc2,0x02},
{0xc3,0x02},
{0xc4,0x02},
{0xc5,0x02},
{0xc6,0x02},
{0xc7,0x02},
{0xc8,0x02},
{0xc9,0x02},
{0xca,0x02},
{0xcb,0x02},
{0xcc,0x02},
{0xcd,0x02},
{0xce,0x02},
{0xcf,0x02},
{0xd0,0x02},
{0xd1,0x02},
{0xd2,0x02},
{0xd3,0x02},
{0xd4,0x02},
{0xd5,0x02},
{0xd6,0x02},
{0xd7,0x02},
{0xd8,0x02},
{0xd9,0x02},
{0xda,0x02},
{0xdb,0x02},
{0xdc,0x02},
{0xdd,0x02},
{0xde,0x02},
{0xdf,0x02},
{0xe0,0x02},
{0xe1,0x02},
{0xe2,0x02},
{0xe3,0x02},
{0xe4,0x02},
{0xe5,0x02},
{0xe6,0x02},
{0xe7,0x02},
{0xe8,0x02},
{0xe9,0x02},
{0xea,0x02},
{0xeb,0x02},
{0xec,0x02},
{0xed,0x02},
{0xee,0x02},
{0xef,0x02},
{0xf0,0x02},
{0xf1,0x02},
{0xf2,0x02},
{0xf3,0x02},
{0xf4,0x02},
{0xf5,0x02},
{0xf6,0x02},
{0xf7,0x02},
{0xf8,0x02},
{0xf9,0x02},
{0xfa,0x02},
{0xfb,0x02},
{0xfc,0x02},
{0xfd,0x02},
{0xfe,0x02},



{0xff,0x01},
{0x4f,0x10},

{0xff,0x02},
{0x80,0xb0},
{0x82,0xb0},





#endif
};


/*
 * Here we'll try to encapsulate the changes for just the output
 * video format.
 * 
 */


static struct regval_list sensor_fmt_yuv422_yuyv[] = {
	//{0x24,0xa2},	//YCbYCr
};

static struct regval_list sensor_fmt_yuv422_yvyu[] = {
	//{0x24,0xa3},	//YCrYCb
};

static struct regval_list sensor_fmt_yuv422_vyuy[] = {
	//{0x24,0xa1},	//CrYCbY
};

static struct regval_list sensor_fmt_yuv422_uyvy[] = {
	//{0x24,0xa0},	//CbYCrY
};

static struct regval_list sensor_fmt_raw[] = {
	//{0x24,0xb7},//raw
};



/*
 * Low-level register I/O.
 *
 */


/*
 * On most platforms, we'd rather do straight i2c I/O.
 */
static int sensor_read(struct v4l2_subdev *sd, unsigned char reg,
    unsigned char *value) //!!!!be careful of the para type!!!
{
	int ret=0;
	int cnt=0;
	
  ret = cci_read_a8_d8(sd,reg,value);
  while(ret!=0&&cnt<2)
  {
  	ret = cci_read_a8_d8(sd,reg,value);
  	cnt++;
  }
  if(cnt>0)
  	vfe_dev_dbg("sensor read retry=%d\n",cnt);
  
  return ret;
}

static int sensor_write(struct v4l2_subdev *sd, unsigned char reg,
    unsigned char value)
{
	int ret=0;
	int cnt=0;
#if 1
  ret = cci_write_a8_d8(sd,reg,value);
  while(ret!=0&&cnt<2)
  {
  	ret = cci_write_a8_d8(sd,reg,value);
  	cnt++;
  }
  if(cnt>0)
  	vfe_dev_dbg("sensor write retry=%d\n",cnt);
  
  return ret;
 #else
	return 0;
 #endif
}

void ColorBar_register_table(struct v4l2_subdev *sd)
{
	cci_write_a8_d8(sd,0xff,0x01);
	cci_write_a8_d8(sd,0x4f,cci_read_a8_d8(sd, 0xb8,0x4f)|0x10);
	cci_write_a8_d8(sd,0xff,0x02);
	cci_write_a8_d8(sd,0x80,cci_read_a8_d8(sd, 0xb8,0x80)| 0xb0);
	cci_write_a8_d8(sd,0x82,0xb0);

	#if 0
IIC_Write(0xb8,0xff,0x01);
IIC_Write(0xb8,0x4f,(IIC_Read(0xb8,0x4f))|0x10);
IIC_Write(0xb8,0xff,0x02);
IIC_Write(0xb8,0x80,(IIC_Read(0xb8,0x80))|0xb0);
IIC_Write(0xb8,0x82,0xB0);	// 20H -> 1280x720p30fps; 30H -> 1280x720p25fps; A0H -> 1080P30fps; B0H->1080P25FPS 
#endif
}

/*
 * Write a list of register settings;
 */
static int sensor_write_array(struct v4l2_subdev *sd, struct regval_list *regs, int array_size)
{
	int i=0;
	
  if(!regs)
  	return 0;
  	//return -EINVAL;
  
  while(i<array_size)
  {
    if(regs->addr == REG_DLY) {
      msleep(regs->data);
    } 
    else 
	{
    	//printk("write 0x%x=0x%x\n", regs->addr, regs->data);
      	LOG_ERR_RET(sensor_write(sd, regs->addr, regs->data))
    }
    i++;
    regs++;
  }
  return 0;
}

static int sensor_g_hflip(struct v4l2_subdev *sd, __s32 *value)
{

	int ret;
	struct sensor_info *info = to_state(sd);
	unsigned char val;
#if 0	
	ret = sensor_write(sd, 0xfe, 0x00);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_g_hflip!\n");
		return ret;
	}
	
	ret = sensor_read(sd, 0x14, &val);
	if (ret < 0) {
		vfe_dev_err("sensor_read err at sensor_g_hflip!\n");
		return ret;
	}
	
	val &= (1<<0);
	val = val>>0;		//0x14 bit0 is mirror
		
	*value = val;

	info->hflip = *value;
	return 0;
#else
	*value = info->hflip;
	return 0;
#endif
}

static int sensor_s_hflip(struct v4l2_subdev *sd, int value)
{
	int ret;
	struct sensor_info *info = to_state(sd);
	unsigned char val;
#if 0
	ret = sensor_write(sd, 0xfe, 0x00);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_s_hflip!\n");
		return ret;
	}
	
	ret = sensor_read(sd, 0x14, &val);
	if (ret < 0) {
		vfe_dev_err("sensor_read err at sensor_s_hflip!\n");
		return ret;
	}
	
	switch (value) {
		case 0:
		  val &= 0xfc;
			break;
		case 1:
			val |= (0x01|(info->vflip<<1));
			break;
		default:
			return -EINVAL;
	}
	ret = sensor_write(sd, 0x14, val);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_s_hflip!\n");
		return ret;
	}
	
	usleep_range(10000,12000);
#endif
	info->hflip = value;
	return 0;
}

static int sensor_g_vflip(struct v4l2_subdev *sd, __s32 *value)
{
	int ret;
	struct sensor_info *info = to_state(sd);
	unsigned char val;

#if 0
	ret = sensor_write(sd, 0xfe, 0x00);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_g_vflip!\n");
		return ret;
	}
	
	ret = sensor_read(sd, 0x14, &val);
	if (ret < 0) {
		vfe_dev_err("sensor_read err at sensor_g_vflip!\n");
		return ret;
	}
	
	val &= (1<<1);
	val = val>>1;		//0x14 bit1 is upsidedown
		
	*value = val;

	info->vflip = *value;
	return 0;
#else
	*value = info->vflip;
	return 0;
#endif
}

static int sensor_s_vflip(struct v4l2_subdev *sd, int value)
{
	int ret;
	struct sensor_info *info = to_state(sd);
	unsigned char val;
#if 0
	ret = sensor_write(sd, 0xfe, 0x00);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_s_vflip!\n");
		return ret;
	}
	
	ret = sensor_read(sd, 0x14, &val);
	if (ret < 0) {
		vfe_dev_err("sensor_read err at sensor_s_vflip!\n");
		return ret;
	}
	
	switch (value) {
		case 0:
		  val &= 0xfc;
			break;
		case 1:
			val |= (0x02|info->hflip);
			break;
		default:
			return -EINVAL;
	}
	ret = sensor_write(sd, 0x14, val);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_s_vflip!\n");
		return ret;
	}
	
	usleep_range(10000,12000);
#endif	
	info->vflip = value;
	return 0;
}

static int sensor_g_autogain(struct v4l2_subdev *sd, __s32 *value)
{
	return -EINVAL;
}

static int sensor_s_autogain(struct v4l2_subdev *sd, int value)
{
	return -EINVAL;
}

static int sensor_g_autoexp(struct v4l2_subdev *sd, __s32 *value)
	{
		return -EINVAL;
	}


static int sensor_s_autoexp(struct v4l2_subdev *sd,
		enum v4l2_exposure_auto_type value)
	{
		return -EINVAL;
	}


static int sensor_g_autowb(struct v4l2_subdev *sd, int *value)
	{
		return -EINVAL;
	}


static int sensor_s_autowb(struct v4l2_subdev *sd, int value)
	{
		return -EINVAL;
	}


static int sensor_g_hue(struct v4l2_subdev *sd, __s32 *value)
{
	return -EINVAL;
}

static int sensor_s_hue(struct v4l2_subdev *sd, int value)
{
	return -EINVAL;
}

static int sensor_g_gain(struct v4l2_subdev *sd, __s32 *value)
{
	return -EINVAL;
}

static int sensor_s_gain(struct v4l2_subdev *sd, int value)
{
	return -EINVAL;
}
/* *********************************************end of ******************************************** */

static int sensor_g_brightness(struct v4l2_subdev *sd, __s32 *value)
	{
		return -EINVAL;
	}


static int sensor_s_brightness(struct v4l2_subdev *sd, int value)
	{
		return -EINVAL;
	}


static int sensor_g_contrast(struct v4l2_subdev *sd, __s32 *value)
	{
		return -EINVAL;
	}


static int sensor_s_contrast(struct v4l2_subdev *sd, int value)
	{
		return -EINVAL;
	}


static int sensor_g_saturation(struct v4l2_subdev *sd, __s32 *value)
	{
		return -EINVAL;
	}


static int sensor_s_saturation(struct v4l2_subdev *sd, int value)
	{
		return -EINVAL;
	}


static int sensor_g_exp_bias(struct v4l2_subdev *sd, __s32 *value)
	{
		return -EINVAL;
	}


static int sensor_s_exp_bias(struct v4l2_subdev *sd, int value)
	{
		return -EINVAL;
	}


static int sensor_g_wb(struct v4l2_subdev *sd, int *value)
	{
		return -EINVAL;
	}


static int sensor_s_wb(struct v4l2_subdev *sd,
    enum v4l2_auto_n_preset_white_balance value)
	{
		return -EINVAL;
	}


static int sensor_g_colorfx(struct v4l2_subdev *sd,
		__s32 *value)
	{
		return -EINVAL;
	}


static int sensor_s_colorfx(struct v4l2_subdev *sd,
    enum v4l2_colorfx value)
	{
		return -EINVAL;
	}


static int sensor_g_flash_mode(struct v4l2_subdev *sd,
    __s32 *value)
{
  struct sensor_info *info = to_state(sd);
  enum v4l2_flash_led_mode *flash_mode = (enum v4l2_flash_led_mode*)value;
  
  *flash_mode = info->flash_mode;
  return 0;
}

static int sensor_s_flash_mode(struct v4l2_subdev *sd,
    enum v4l2_flash_led_mode value)
{
  struct sensor_info *info = to_state(sd);
//  struct vfe_dev *dev=(struct vfe_dev *)dev_get_drvdata(sd->v4l2_dev->dev);
//  int flash_on,flash_off;
//  
//  flash_on = (dev->flash_pol!=0)?1:0;
//  flash_off = (flash_on==1)?0:1;
//  
//  switch (value) {
//  case V4L2_FLASH_MODE_OFF:
//    os_gpio_write(&dev->flash_io,flash_off);
//    break;
//  case V4L2_FLASH_MODE_AUTO:
//    return -EINVAL;
//    break;  
//  case V4L2_FLASH_MODE_ON:
//    os_gpio_write(&dev->flash_io,flash_on);
//    break;   
//  case V4L2_FLASH_MODE_TORCH:
//    return -EINVAL;
//    break;
//  case V4L2_FLASH_MODE_RED_EYE:   
//    return -EINVAL;
//    break;
//  default:
//    return -EINVAL;
//  }
  
  info->flash_mode = value;
  return 0;
}

//static int sensor_s_sw_stby(struct v4l2_subdev *sd, int on_off)
//{
//	int ret=0;
////	unsigned char rdval;
////	
////	ret=sensor_read(sd, 0x00, &rdval);
////	if(ret!=0)
////		return ret;
////	
////	if(on_off==CSI_STBY_ON)//sw stby on
////	{
////		ret=sensor_write(sd, 0x00, rdval&0x7f);
////	}
////	else//sw stby off
////	{
////		ret=sensor_write(sd, 0x00, rdval|0x80);
////	}
//	return ret;
//}

/*
 * Stuff that knows about the sensor.
 */
 
static int sensor_power(struct v4l2_subdev *sd, int on)
{
  //make sure that no device can access i2c bus during sensor initial or power down
  //when using i2c_lock_adpater function, the following codes must not access i2c bus before calling i2c_unlock_adapter
  cci_lock(sd);
  
  //insure that clk_disable() and clk_enable() are called in pair 
  //when calling CSI_SUBDEV_STBY_ON/OFF and CSI_SUBDEV_PWR_ON/OFF  
  switch(on)
  {
    case CSI_SUBDEV_STBY_ON:
      vfe_dev_dbg("CSI_SUBDEV_STBY_ON\n");
      //standby on io
      vfe_gpio_write(sd,PWDN,CSI_STBY_ON);
      usleep_range(30000,31000);
      //inactive mclk after stadby in
      vfe_set_mclk(sd,OFF);
      break;
    case CSI_SUBDEV_STBY_OFF:
      vfe_dev_dbg("CSI_SUBDEV_STBY_OFF\n");
      //active mclk before stadby out
      vfe_set_mclk_freq(sd,MCLK);
      vfe_set_mclk(sd,ON);
      usleep_range(30000,31000);
      //standby off io
      vfe_gpio_write(sd,PWDN,CSI_STBY_OFF);
      usleep_range(10000,12000);
//			//reset off io
//			csi_gpio_write(sd,&dev->reset_io,CSI_RST_OFF);
//			usleep_range(30000,31000);
      break;
    case CSI_SUBDEV_PWR_ON:
      vfe_dev_dbg("CSI_SUBDEV_PWR_ON\n");
      //power on reset
      vfe_gpio_set_status(sd,PWDN,1);//set the gpio to output
      vfe_gpio_set_status(sd,RESET,1);//set the gpio to output
      usleep_range(10000,12000);
      //standby off io
      vfe_gpio_write(sd,PWDN,CSI_STBY_ON);
			//reset on io
      vfe_gpio_write(sd,RESET,CSI_RST_ON);
      //power supply
      vfe_gpio_write(sd,POWER_EN,CSI_PWR_ON);
      vfe_set_pmu_channel(sd,IOVDD,ON);
      vfe_set_pmu_channel(sd,AVDD,ON);
      vfe_set_pmu_channel(sd,DVDD,ON);
      vfe_set_pmu_channel(sd,AFVDD,ON);
      usleep_range(20000,22000);
      //standby off io
      vfe_gpio_write(sd,PWDN,CSI_STBY_OFF);
      usleep_range(10000,12000);
			//active mclk
      vfe_set_mclk_freq(sd,MCLK);
      vfe_set_mclk(sd,ON);
      usleep_range(10000,12000);
			//reset on io
      vfe_gpio_write(sd,RESET,CSI_RST_ON);
			usleep_range(30000,31000);
			//reset off io
      vfe_gpio_write(sd,RESET,CSI_RST_OFF);
			usleep_range(30000,31000);
			break;
		case CSI_SUBDEV_PWR_OFF:
      vfe_dev_dbg("CSI_SUBDEV_PWR_OFF\n");
      //reset io
      usleep_range(10000,12000);
      vfe_gpio_write(sd,RESET,CSI_RST_ON);
			usleep_range(10000,12000);
			//inactive mclk after power off
      vfe_set_mclk(sd,OFF);
      //power supply off
      vfe_gpio_write(sd,POWER_EN,CSI_PWR_OFF);
      vfe_set_pmu_channel(sd,AFVDD,OFF);
      vfe_set_pmu_channel(sd,DVDD,OFF);
      vfe_set_pmu_channel(sd,AVDD,OFF);
      vfe_set_pmu_channel(sd,IOVDD,OFF);  
      usleep_range(10000,12000);
      //standby and reset io
			//standby of io
      vfe_gpio_write(sd,PWDN,CSI_STBY_ON);
      usleep_range(10000,12000);
      //set the io to hi-z
      vfe_gpio_set_status(sd,RESET,0);//set the gpio to input
      vfe_gpio_set_status(sd,PWDN,0);//set the gpio to input
			break;
		default:
			return -EINVAL;
	}		

	//remember to unlock i2c adapter, so the device can access the i2c bus again
	cci_unlock(sd);	
	return 0;
}
 
static int sensor_reset(struct v4l2_subdev *sd, u32 val)
{
  switch(val)
  {
    case 0:
      vfe_gpio_write(sd,RESET,CSI_RST_OFF);
      usleep_range(10000,12000);
      break;
    case 1:
      vfe_gpio_write(sd,RESET,CSI_RST_ON);
      usleep_range(10000,12000);
      break;
    default:
      return -EINVAL;
  }
    
  return 0;
}

static int sensor_detect(struct v4l2_subdev *sd)
{
#if 0
	int ret;
	unsigned char val;
	
	ret = sensor_write(sd, 0xfe, 0x00);
	if (ret < 0) {
		vfe_dev_err("sensor_write err at sensor_detect!\n");
		return ret;
	}
	
	ret = sensor_read(sd, 0x00, &val);
	if (ret < 0) {
		vfe_dev_err("sensor_read err at sensor_detect!\n");
		return ret;
	}

	if(val != 0x9b)
		return -ENODEV;
#endif
	return 0;
}

extern 	void *g_pV4l2_subdev;
extern int pr2000_module_init(void);
static int sensor_init(struct v4l2_subdev *sd, u32 val)
{
#if 0
	int ret;
	vfe_dev_dbg("sensor_init\n");
	
	/*Make sure it is a target sensor*/
	ret = sensor_detect(sd);
	if (ret) {
		vfe_dev_err("chip found is not an target chip.\n");
		return ret;
	}

	return sensor_write_array(sd, sensor_default_regs , ARRAY_SIZE(sensor_default_regs));
#else
	//return sensor_write_array(sd, sensor_default_regs , ARRAY_SIZE(sensor_default_regs));
	if (NULL == g_pV4l2_subdev)
	{
		g_pV4l2_subdev = sd;
		pr2000_module_init();
	}
	
	return 0;
#endif
}

static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
	int ret=0;

	return ret;
}


/*
 * Store information about the video data format. 
 */
static struct sensor_format_struct {
	__u8 *desc;
	//__u32 pixelformat;
	enum v4l2_mbus_pixelcode mbus_code;//linux-3.0
	struct regval_list *regs;
	int	regs_size;
	int bpp;   /* Bytes per pixel */
} sensor_formats[] = {
	{
		.desc		= "YUYV 4:2:2",
		.mbus_code	= V4L2_MBUS_FMT_YUYV8_2X8,//linux-3.0
		.regs 		= sensor_fmt_yuv422_yuyv,
		.regs_size = ARRAY_SIZE(sensor_fmt_yuv422_yuyv),
		.bpp		= 2,
	},
	{
		.desc		= "YVYU 4:2:2",
		.mbus_code	= V4L2_MBUS_FMT_YVYU8_2X8,//linux-3.0
		.regs 		= sensor_fmt_yuv422_yvyu,
		.regs_size = ARRAY_SIZE(sensor_fmt_yuv422_yvyu),
		.bpp		= 2,
	},
	{
		.desc		= "UYVY 4:2:2",
		.mbus_code	= V4L2_MBUS_FMT_UYVY8_2X8,//linux-3.0
		.regs 		= sensor_fmt_yuv422_uyvy,
		.regs_size = ARRAY_SIZE(sensor_fmt_yuv422_uyvy),
		.bpp		= 2,
	},
	{
		.desc		= "VYUY 4:2:2",
		.mbus_code	= V4L2_MBUS_FMT_VYUY8_2X8,//linux-3.0
		.regs 		= sensor_fmt_yuv422_vyuy,
		.regs_size = ARRAY_SIZE(sensor_fmt_yuv422_vyuy),
		.bpp		= 2,
	},
	
};
#define N_FMTS ARRAY_SIZE(sensor_formats)


/*
 * Then there is the issue of window sizes.  Try to capture the info here.
 */


static struct sensor_win_size 
sensor_win_sizes[] = {
#if 0
  {
    .width      = HD1080_WIDTH,
    .height     = HD1080_HEIGHT,
    .hoffset    = 0,
    .voffset    = 0,
    .regs       = NULL,
    .regs_size  = 0,
    .set_size   = NULL,
  },
 #endif
 
 #if 0
  {
    .width      = HD720_WIDTH,
    .height     = HD720_HEIGHT,
    .hoffset    = 0,
    .voffset    = 0,
    .regs       = NULL,
    .regs_size  = 0,
    .set_size   = NULL,
  },
  #endif
  #if 1
  {
    .width      = 960,
    .height     = 480,
    .hoffset    = 0,
    .voffset    = 0,
    .regs       = NULL,
    .regs_size  = 0,
    .set_size   = NULL,
  },
 #endif
};

#define N_WIN_SIZES (ARRAY_SIZE(sensor_win_sizes))

static int sensor_enum_fmt(struct v4l2_subdev *sd, unsigned index,
                 enum v4l2_mbus_pixelcode *code)
{
  if (index >= N_FMTS)
    return -EINVAL;

  *code = sensor_formats[index].mbus_code;
  return 0;
}

static int sensor_enum_size(struct v4l2_subdev *sd,
                            struct v4l2_frmsizeenum *fsize)
{
  if(fsize->index > N_WIN_SIZES-1)
  	return -EINVAL;
  
  fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
  fsize->discrete.width = sensor_win_sizes[fsize->index].width;
  fsize->discrete.height = sensor_win_sizes[fsize->index].height;
  
  return 0;
}


static int sensor_try_fmt_internal(struct v4l2_subdev *sd,
    struct v4l2_mbus_framefmt *fmt,
    struct sensor_format_struct **ret_fmt,
    struct sensor_win_size **ret_wsize)
{
  int index;
  struct sensor_win_size *wsize;

  for (index = 0; index < N_FMTS; index++)
    if (sensor_formats[index].mbus_code == fmt->code)
      break;

  if (index >= N_FMTS) 
    return -EINVAL;
  
  if (ret_fmt != NULL)
    *ret_fmt = sensor_formats + index;
    
  /*
   * Fields: the sensor devices claim to be progressive.
   */
  
  fmt->field = V4L2_FIELD_INTERLACED;//;V4L2_FIELD_NONE
  fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
  
  /*
   * Round requested image size down to the nearest
   * we support, but not below the smallest.
   */
  for (wsize = sensor_win_sizes; wsize < sensor_win_sizes + N_WIN_SIZES;
       wsize++)
    if (fmt->width >= wsize->width && fmt->height >= wsize->height)
      break;
    
  if (wsize >= sensor_win_sizes + N_WIN_SIZES)
    wsize--;   /* Take the smallest one */
  if (ret_wsize != NULL)
    *ret_wsize = wsize;
  /*
   * Note the size we'll actually handle.
   */
  fmt->width = wsize->width;
  fmt->height = wsize->height;
  fmt->reserved[0] = wsize->hoffset;
  fmt->reserved[1] = wsize->voffset;
  //pix->bytesperline = pix->width*sensor_formats[index].bpp;
  //pix->sizeimage = pix->height*pix->bytesperline;

  return 0;
}

static int sensor_try_fmt(struct v4l2_subdev *sd, 
             struct v4l2_mbus_framefmt *fmt)//linux-3.0
{
	return sensor_try_fmt_internal(sd, fmt, NULL, NULL);
}

static int sensor_g_mbus_config(struct v4l2_subdev *sd,
           struct v4l2_mbus_config *cfg)
{
  cfg->type = V4L2_MBUS_BT656;//;V4L2_MBUS_PARALLEL
  cfg->flags = V4L2_MBUS_MASTER | VREF_POL | HREF_POL | CLK_POL ;
  
  return 0;
}

/*
 * Set a format.
 */
static int sensor_s_fmt(struct v4l2_subdev *sd, 
             struct v4l2_mbus_framefmt *fmt)//linux-3.0
{
	int ret;
	struct sensor_format_struct *sensor_fmt;
	struct sensor_win_size *wsize;
	struct sensor_info *info = to_state(sd);
	vfe_dev_dbg("sensor_s_fmt\n");
	ret = sensor_try_fmt_internal(sd, fmt, &sensor_fmt, &wsize);
	if (ret)
		return ret;
	#if 0
	sensor_write_array(sd, sensor_fmt->regs , sensor_fmt->regs_size);
	
	ret = 0;
	if (wsize->regs)
	{
		ret = sensor_write_array(sd, wsize->regs , wsize->regs_size);
		if (ret < 0)
			return ret;
	}
	
	if (wsize->set_size)
	{
		ret = wsize->set_size(sd);
		if (ret < 0)
			return ret;
	}
	#endif
	info->fmt = sensor_fmt;
	info->width = wsize->width;
	info->height = wsize->height;
	return 0;
}

/*
 * Implement G/S_PARM.  There is a "high quality" mode we could try
 * to do someday; for now, we just do the frame rate tweak.
 */
static int sensor_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{
	struct v4l2_captureparm *cp = &parms->parm.capture;
	//struct sensor_info *info = to_state(sd);

	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	memset(cp, 0, sizeof(struct v4l2_captureparm));
	cp->capability = V4L2_CAP_TIMEPERFRAME;
	cp->timeperframe.numerator = 1;
	cp->timeperframe.denominator = SENSOR_FRAME_RATE;
	
	return 0;
}

static int sensor_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{
//	struct v4l2_captureparm *cp = &parms->parm.capture;
	//struct v4l2_fract *tpf = &cp->timeperframe;
	//struct sensor_info *info = to_state(sd);
	//int div;

//	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
//		return -EINVAL;
//	if (cp->extendedmode != 0)
//		return -EINVAL;

//	if (tpf->numerator == 0 || tpf->denominator == 0)
//		div = 1;  /* Reset to full rate */
//	else
//		div = (tpf->numerator*SENSOR_FRAME_RATE)/tpf->denominator;
//		
//	if (div == 0)
//		div = 1;
//	else if (div > CLK_SCALE)
//		div = CLK_SCALE;
//	info->clkrc = (info->clkrc & 0x80) | div;
//	tpf->numerator = 1;
//	tpf->denominator = sensor_FRAME_RATE/div;
//sensor_write(sd, REG_CLKRC, info->clkrc);
	return 0;
}


/* 
 * Code for dealing with controls.
 * fill with different sensor module
 * different sensor module has different settings here
 * if not support the follow function ,retrun -EINVAL
 */

/* *********************************************begin of ******************************************** */
static int sensor_queryctrl(struct v4l2_subdev *sd,
		struct v4l2_queryctrl *qc)
{
	/* Fill in min, max, step and default value for these controls. */
	/* see include/linux/videodev2.h for details */
	/* see sensor_s_parm and sensor_g_parm for the meaning of value */
	
	switch (qc->id) {
//	case V4L2_CID_BRIGHTNESS:
//		return v4l2_ctrl_query_fill(qc, -4, 4, 1, 1);
//	case V4L2_CID_CONTRAST:
//		return v4l2_ctrl_query_fill(qc, -4, 4, 1, 1);
//	case V4L2_CID_SATURATION:
//		return v4l2_ctrl_query_fill(qc, -4, 4, 1, 1);
//	case V4L2_CID_HUE:
//		return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
	case V4L2_CID_VFLIP:
	case V4L2_CID_HFLIP:
		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
//	case V4L2_CID_GAIN:
//		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
//	case V4L2_CID_AUTOGAIN:
//		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
	case V4L2_CID_EXPOSURE:
  case V4L2_CID_AUTO_EXPOSURE_BIAS:
		return v4l2_ctrl_query_fill(qc, -4, 4, 1, 0);
	case V4L2_CID_EXPOSURE_AUTO:
		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
  case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
    return v4l2_ctrl_query_fill(qc, 0, 9, 1, 1);
	case V4L2_CID_AUTO_WHITE_BALANCE:
		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
	case V4L2_CID_COLORFX:
    return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0);
  case V4L2_CID_FLASH_LED_MODE:
	  return v4l2_ctrl_query_fill(qc, 0, 4, 1, 0);	
	}
	return -EINVAL;
}


static int sensor_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
		return sensor_g_brightness(sd, &ctrl->value);
	case V4L2_CID_CONTRAST:
		return sensor_g_contrast(sd, &ctrl->value);
	case V4L2_CID_SATURATION:
		return sensor_g_saturation(sd, &ctrl->value);
	case V4L2_CID_HUE:
		return sensor_g_hue(sd, &ctrl->value);	
	case V4L2_CID_VFLIP:
		return sensor_g_vflip(sd, &ctrl->value);
	case V4L2_CID_HFLIP:
		return sensor_g_hflip(sd, &ctrl->value);
	case V4L2_CID_GAIN:
		return sensor_g_gain(sd, &ctrl->value);
	case V4L2_CID_AUTOGAIN:
		return sensor_g_autogain(sd, &ctrl->value);
	case V4L2_CID_EXPOSURE:
  case V4L2_CID_AUTO_EXPOSURE_BIAS:
    return sensor_g_exp_bias(sd, &ctrl->value);
  case V4L2_CID_EXPOSURE_AUTO:
    return sensor_g_autoexp(sd, &ctrl->value);
  case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
    return sensor_g_wb(sd, &ctrl->value);
  case V4L2_CID_AUTO_WHITE_BALANCE:
    return sensor_g_autowb(sd, &ctrl->value);
  case V4L2_CID_COLORFX:
    return sensor_g_colorfx(sd, &ctrl->value);
  case V4L2_CID_FLASH_LED_MODE:
    return sensor_g_flash_mode(sd, &ctrl->value);
	}
	return -EINVAL;
}

static int sensor_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
  struct v4l2_queryctrl qc;
  int ret;
  
//  vfe_dev_dbg("sensor_s_ctrl ctrl->id=0x%8x\n", ctrl->id);
  qc.id = ctrl->id;
  ret = sensor_queryctrl(sd, &qc);
  if (ret < 0) {
    return ret;
  }

	if (qc.type == V4L2_CTRL_TYPE_MENU ||
		qc.type == V4L2_CTRL_TYPE_INTEGER ||
		qc.type == V4L2_CTRL_TYPE_BOOLEAN)
	{
	  if (ctrl->value < qc.minimum || ctrl->value > qc.maximum) {
	    return -ERANGE;
	  }
	}
	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
		return sensor_s_brightness(sd, ctrl->value);
	case V4L2_CID_CONTRAST:
		return sensor_s_contrast(sd, ctrl->value);
	case V4L2_CID_SATURATION:
		return sensor_s_saturation(sd, ctrl->value);
	case V4L2_CID_HUE:
		return sensor_s_hue(sd, ctrl->value);		
	case V4L2_CID_VFLIP:
		return sensor_s_vflip(sd, ctrl->value);
	case V4L2_CID_HFLIP:
		return sensor_s_hflip(sd, ctrl->value);
	case V4L2_CID_GAIN:
		return sensor_s_gain(sd, ctrl->value);
	case V4L2_CID_AUTOGAIN:
		return sensor_s_autogain(sd, ctrl->value);
	case V4L2_CID_EXPOSURE:
    case V4L2_CID_AUTO_EXPOSURE_BIAS:
      return sensor_s_exp_bias(sd, ctrl->value);
    case V4L2_CID_EXPOSURE_AUTO:
      return sensor_s_autoexp(sd,
          (enum v4l2_exposure_auto_type) ctrl->value);
    case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
  		return sensor_s_wb(sd,
          (enum v4l2_auto_n_preset_white_balance) ctrl->value); 
    case V4L2_CID_AUTO_WHITE_BALANCE:
      return sensor_s_autowb(sd, ctrl->value);
    case V4L2_CID_COLORFX:
      return sensor_s_colorfx(sd,
          (enum v4l2_colorfx) ctrl->value);
    case V4L2_CID_FLASH_LED_MODE:
      return sensor_s_flash_mode(sd,
          (enum v4l2_flash_led_mode) ctrl->value);
	}
	return -EINVAL;
}


static int sensor_g_chip_ident(struct v4l2_subdev *sd,
		struct v4l2_dbg_chip_ident *chip)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SENSOR, 0);
}


/* ----------------------------------------------------------------------- */

static const struct v4l2_subdev_core_ops sensor_core_ops = {
	.g_chip_ident = sensor_g_chip_ident,
	.g_ctrl = sensor_g_ctrl,
	.s_ctrl = sensor_s_ctrl,
	.queryctrl = sensor_queryctrl,
	.reset = sensor_reset,
	.init = sensor_init,
	.s_power = sensor_power,
	.ioctl = sensor_ioctl,
};

static const struct v4l2_subdev_video_ops sensor_video_ops = {
  .enum_mbus_fmt = sensor_enum_fmt,
  .enum_framesizes = sensor_enum_size,
  .try_mbus_fmt = sensor_try_fmt,
  .s_mbus_fmt = sensor_s_fmt,
  .s_parm = sensor_s_parm,
  .g_parm = sensor_g_parm,
  .g_mbus_config = sensor_g_mbus_config,
};

static const struct v4l2_subdev_ops sensor_ops = {
	.core = &sensor_core_ops,
	.video = &sensor_video_ops,
};

/* ----------------------------------------------------------------------- */
static struct cci_driver cci_drv = {
	.name = SENSOR_NAME,
	.addr_width = CCI_BITS_8,
	.data_width = CCI_BITS_8,
};

extern void pr2000_module_exit(void);

static int sensor_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct v4l2_subdev *sd;
	struct sensor_info *info;

	info = kzalloc(sizeof(struct sensor_info), GFP_KERNEL);
	if (info == NULL)
		return -ENOMEM;
	sd = &info->sd;
	cci_dev_probe_helper(sd, client, &sensor_ops, &cci_drv);

	info->fmt = &sensor_formats[0];
	info->brightness = 0;
	info->contrast = 0;
	info->saturation = 0;
	info->hue = 0;
	info->hflip = 0;
	info->vflip = 0;
	info->gain = 0;
	info->autogain = 1;
	info->exp = 0;
	info->autoexp = 0;
	info->autowb = 1;
	info->wb = 0;
	info->clrfx = 0;
	return 0;
}


static int sensor_remove(struct i2c_client *client)
{
	struct v4l2_subdev *sd;
	pr2000_module_exit();
	sd = cci_dev_remove_helper(client, &cci_drv);
	kfree(to_state(sd));
	return 0;
}

static const struct i2c_device_id sensor_id[] = {
	{SENSOR_NAME, 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, sensor_id);

//linux-3.0
static struct i2c_driver sensor_driver = {
	.driver = {
		.owner = THIS_MODULE,
	  .name = SENSOR_NAME,
	},
	.probe = sensor_probe,
	.remove = sensor_remove,
	.id_table = sensor_id,
};

static __init int init_sensor(void)
{
	cci_dev_init_helper(&sensor_driver);
	return 0;
}

static __exit void exit_sensor(void)
{
	cci_dev_exit_helper(&sensor_driver);
}

module_init(init_sensor);
module_exit(exit_sensor);
